unit clipboardhelper;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, Clipbrd, fpjson, LCLType;

type

  { TClipboardArraySerializer }

  TClipboardArraySerializer = class
    private
      Stream: TMemoryStream;
      NumItems: Integer;
      FormatId: TClipboardFormat;
    public
      constructor Create(AFormatId: TClipboardFormat);
      destructor Destroy; override;
      procedure AddItem(Item: TJSONObject);
      procedure CopyToClipboard;
  end;

const
  DataTypeStrings: array [1..28] of String = (
    'application/rpgmv-event',
    'application/rpgmv-EventCommand',
    'application/rpgmv-actors',
    'application/rpgmv-classes',
    'application/rpgmv-skills',
    'application/rpgmv-items',
    'application/rpgmv-weapons',
    'application/rpgmv-armors',
    'application/rpgmv-enemies',
    'application/rpgmv-troops',
    'application/rpgmv-states',
    'application/rpgmv-animations',
    'application/rpgmv-tilesets',
    'application/rpgmv-commonEvents',
    'application/rpgmv-partyMembers',
    'application/rpgmv-elements',
    'application/rpgmv-skillTypes',
    'application/rpgmv-weaponTypes',
    'application/rpgmv-armorTypes',
    'application/rpgmv-equipTypes',
    'application/rpgmv-map',
    'application/rpgmv-partyMembers',
    'application/rpgmv-learnings',
    'application/rpgmv-traits',
    'application/rpgmv-effects',
    'application/rpgmv-actions',
    'application/rpgmv-BattleEventPage',
    'application/rpgmv-EventPage'
  );

  DATA_TYPE_ID_EVENT_COMMAND = 2;
  DATA_TYPE_ID_TRAITS = 24;
  DATA_TYPE_ID_EFFECTS = 25;
  DATA_TYPE_ID_ACTIONS = 26;
  DATA_TYPE_ID_BATTLE_EVENT_PAGE = 27;
  DATA_TYPE_ID_MAP_EVENT_PAGE = 28;

procedure RegisterClipboardTypes;
function GetDataTypeId(Name: String): TClipboardFormat;
function GetDataTypeName(Id: TClipboardFormat): String;
function ClipboardHasData(DataTypeName: String): Boolean;
function GetJsonArrayFromClipboard(DataTypeName: String): TJSONArray;
function GetJsonObjectFromClipboard(DataTypeName: String): TJSONObject;
function GetJsonDataFromClipboard(DataTypeName: String): TJSONData;
procedure CopyDataToClipboard(AFormatId: TClipboardFormat; Data: TJSONData);

var
  DataTypeIds: array [Low(DataTypeStrings)..High(DataTypeStrings)] of TClipboardFormat;

implementation

uses
  jsonparser;

procedure RegisterClipboardTypes;
var
  I: Integer;
begin
  for I := Low(DataTypeStrings) to High(DataTypeStrings) do begin
    DataTypeIds[I] := RegisterClipboardFormat(DataTypeStrings[I]);
  end;
end;

function GetDataTypeId(Name: String): TClipboardFormat;
var
  I: Integer;
begin
  GetDataTypeId := 0;
  for I := Low(DataTypeStrings) to High(DataTypeStrings) do begin
    if DataTypeStrings[I] = Name then begin
      GetDataTypeId := DataTypeIds[I];
      Exit
    end
  end
end;

function GetDataTypeName(Id: TClipboardFormat): String;
var
  I: Integer;
begin
  GetDataTypeName := '';
  for I := Low(DataTypeStrings) to High(DataTypeStrings) do begin
    if DataTypeIds[I] = Id then begin
      GetDataTypeName := DataTypeStrings[I];
      Exit
    end
  end
end;

function ClipboardHasData(DataTypeName: String): Boolean;
begin
  ClipboardHasData := Clipboard.HasFormatName(DataTypeName);
end;

function GetJsonArrayFromClipboard(DataTypeName: String): TJSONArray;
begin
  GetJsonArrayFromClipboard := GetJsonDataFromClipboard(DataTypeName) as TJSONArray
end;

function GetJsonObjectFromClipboard(DataTypeName: String): TJSONObject;
begin
  GetJsonObjectFromClipboard := GetJsonDataFromClipboard(DataTypeName) as TJSONObject
end;

function GetJsonDataFromClipboard(DataTypeName: String): TJSONData;
var
  Stream: TMemoryStream;
  JsonData: TJSONData;
  FormatId, I: Integer;
begin
  GetJsonDataFromClipboard := nil;
  if not Clipboard.HasFormatName(DataTypeName) then
    Exit;

  Stream := TMemoryStream.Create;
  try
    FormatId := Clipboard.FindFormatID(DataTypeName);
    Clipboard.GetFormat(FormatId, Stream);
    if Stream.Size > 0 then begin
      Stream.Seek(0, soFromBeginning);
      JsonData := GetJSON(Stream, True);
      //TODO: sanity checks?
      GetJsonDataFromClipboard := JsonData;
    end;
  finally
    Stream.Free;
  end;
end;

procedure CopyDataToClipboard(AFormatId: TClipboardFormat; Data: TJSONData);
var
  Stream: TMemoryStream;
  AChar: Byte;
  JsonString: String;
begin
  Stream := TMemoryStream.Create;

  JsonString := Data.AsJSON;
  Stream.Write(JsonString[1], Length(JsonString));

  AChar := 0;
  Stream.Write(AChar, 1);
  Stream.Seek(0, soFromBeginning);

  Clipboard.AddFormat(AFormatId, Stream);

  Stream.Clear;
  Stream.Free;
end;

{ TClipboardArraySerializer }

constructor TClipboardArraySerializer.Create(AFormatId: TClipboardFormat);
begin
  Stream := TMemoryStream.Create;
  NumItems := 0;
  FormatId := AFormatId;
end;

destructor TClipboardArraySerializer.Destroy;
begin
  Stream.Destroy;
  inherited;
end;

procedure TClipboardArraySerializer.AddItem(Item: TJSONObject);
var
  AChar: Byte;
  JsonString: String;
begin
  if NumItems = 0 then
    AChar := Ord('[')
  else
    AChar := Ord(',');
  Stream.Write(AChar, 1);

  JsonString := Item.AsJSON;
  Stream.Write(JsonString[1], Length(JsonString));

  Inc(NumItems)
end;

procedure TClipboardArraySerializer.CopyToClipboard;
var
  AChar: Byte;
begin
  AChar := Ord(']');
  Stream.Write(AChar, 1);
  AChar := 0;
  Stream.Write(AChar, 1);
  Stream.Seek(0, soFromBeginning);

  Clipboard.AddFormat(FormatId, Stream);

  NumItems := 0;
  Stream.Clear;
end;

initialization
  RegisterClipboardTypes

end.

